package com.yuanfeng.commoms.aspect;

import com.yuanfeng.commoms.annnotation.RepeatClick;
import com.yuanfeng.commoms.util.ResponseResult;
import org.apache.commons.codec.digest.DigestUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.UUID;

/**
 * @author fzh
 */
@Aspect
@Component
public class RepeatClickAspect {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     *
     * @param joinPoint
     * @param repeatClick
     * @return
     * @throws Throwable
     */
    @Around("@annotation(repeatClick)")
    public Object repeatClick(ProceedingJoinPoint joinPoint, RepeatClick repeatClick) throws Throwable {
        Object[] args = joinPoint.getArgs();
        /*
         * 获取请求信息
         */
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        // 获取执行方法
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        // 获取防重复提交注解
        // 获取token以及方法标记，生成redisKey和redisValue
        String url = request.getRequestURI();
        // redisKey的前缀
        String PREVENT_DUPLICATION_PREFIX = "PREVENT_DUPLICATION_PREFIX:";
        /*
         *  通过前缀 + url  + 函数参数签名 来生成redis上的 key
         */
        String redisKey = PREVENT_DUPLICATION_PREFIX
                .concat(url)
                .concat(getMethodSign(method, joinPoint.getArgs()));
        // 重复点击注解为空  跳过
        if (ObjectUtils.isEmpty(repeatClick)) {
            return joinPoint.proceed(args);
        }
        // 使用错误提示
        if (ObjectUtils.isEmpty(redisKey) || repeatClick.expireSeconds() == 0) {
            return joinPoint.proceed(args);
        }
        if (Boolean.TRUE.equals(redisTemplate.hasKey(redisKey))) {
            return ResponseResult.fail(0,"请勿重复点击");
        }
        redisTemplate.opsForValue().set(redisKey, UUID.randomUUID().toString());
        redisTemplate.expire(redisKey, repeatClick.expireSeconds(), repeatClick.unit());
        return joinPoint.proceed(args);
    }
    /**
     * 生成方法标记：采用数字签名算法SHA1对方法签名字符串加签
     *
     * @param method 1
     * @param args 1
     * @return 1
     */
    private String getMethodSign(Method method, Object... args) {
        StringBuilder sb = new StringBuilder(method.toString());
        Object arg = args[0];
        sb.append(arg);
        return DigestUtils.sha1Hex(sb.toString());
    }
}